<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>node.js --- Buffer | mozihao</title><meta name="keywords" content="Buffer"><meta name="author" content="mozihao"><meta name="copyright" content="mozihao"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="在node中,应用需要处理网络协议、操作数据库、处理图片、接受上传文件等，在网络流和文件的操作中，还要处理大量二进制数据，javaScript自有的字符串远远不能满足这些需求，于是buffer对象应运而生 「buffer是一个像Array的对象，但它主要用于操作字节」。 buffer 是一个javascript与c++结合，buffer所占用的 内存不是通过V8分配的，属于堆外内存，由于V8垃圾回">
<meta property="og:type" content="article">
<meta property="og:title" content="node.js --- Buffer">
<meta property="og:url" content="https://mo_zi_hao.gitee.io/blog/posts/28371/index.html">
<meta property="og:site_name" content="mozihao">
<meta property="og:description" content="在node中,应用需要处理网络协议、操作数据库、处理图片、接受上传文件等，在网络流和文件的操作中，还要处理大量二进制数据，javaScript自有的字符串远远不能满足这些需求，于是buffer对象应运而生 「buffer是一个像Array的对象，但它主要用于操作字节」。 buffer 是一个javascript与c++结合，buffer所占用的 内存不是通过V8分配的，属于堆外内存，由于V8垃圾回">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://gitee.com/mo_zi_hao/picsBed/raw/master/image/%E8%8B%B1%E8%AF%AD%E5%AD%A6%E4%B9%A0%E8%8B%B1%E6%A0%87%E5%A4%A7%E5%85%A8.jpg">
<meta property="article:published_time" content="2020-06-20T06:18:57.000Z">
<meta property="article:modified_time" content="2021-08-29T15:22:14.597Z">
<meta property="article:author" content="mozihao">
<meta property="article:tag" content="Buffer">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://gitee.com/mo_zi_hao/picsBed/raw/master/image/%E8%8B%B1%E8%AF%AD%E5%AD%A6%E4%B9%A0%E8%8B%B1%E6%A0%87%E5%A4%A7%E5%85%A8.jpg"><link rel="shortcut icon" href="/blog/img/favicon.png"><link rel="canonical" href="https://mo_zi_hao.gitee.io/blog/posts/28371/"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/blog/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = { 
  root: '/blog/',
  algolia: undefined,
  localSearch: {"path":"search.xml","languages":{"hits_empty":"找不到您查询的内容：${query}"}},
  translate: {"defaultEncoding":2,"translateDelay":0,"msgToTraditionalChinese":"繁","msgToSimplifiedChinese":"簡"},
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    jQuery: 'https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js',
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/js/jquery.justifiedGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/css/justifiedGallery.min.css'
    },
    fancybox: {
      js: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.js',
      css: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: true,
  isanchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = { 
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2021-08-29 23:22:14'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    })(window)</script><link rel="stylesheet" type="text/css" href="./css/iconfont.css" media="all"><meta name="generator" content="Hexo 5.4.2"><link rel="alternate" href="/blog/atom.xml" title="mozihao" type="application/atom+xml">
</head><body><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="author-avatar"><img class="avatar-img" src="https://gitee.com/mo_zi_hao/picsBed/raw/master/image/%E6%B5%B7%E8%B4%BC008.jpg" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="site-data"><div class="data-item is-center"><div class="data-item-link"><a href="/blog/archives/"><div class="headline">文章</div><div class="length-num">24</div></a></div></div><div class="data-item is-center"><div class="data-item-link"><a href="/blog/tags/"><div class="headline">标签</div><div class="length-num">16</div></a></div></div><div class="data-item is-center"><div class="data-item-link"><a href="/blog/categories/"><div class="headline">分类</div><div class="length-num">11</div></a></div></div></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/blog/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/blog/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/blog/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/blog/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/blog/about/"><i class="fa-fw fas fa-heart"></i><span> 前端知识思维导图</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url('https://gitee.com/mo_zi_hao/picsBed/raw/master/image/%E8%8B%B1%E8%AF%AD%E5%AD%A6%E4%B9%A0%E8%8B%B1%E6%A0%87%E5%A4%A7%E5%85%A8.jpg')"><nav id="nav"><span id="blog_name"><a id="site-name" href="/blog/">mozihao</a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/blog/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/blog/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/blog/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/blog/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/blog/about/"><i class="fa-fw fas fa-heart"></i><span> 前端知识思维导图</span></a></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">node.js --- Buffer</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2020-06-20T06:18:57.000Z" title="发表于 2020-06-20 14:18:57">2020-06-20</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2021-08-29T15:22:14.597Z" title="更新于 2021-08-29 23:22:14">2021-08-29</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/blog/categories/node/">node</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">4.1k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>15分钟</span></span><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="node.js --- Buffer"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"></span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><p>在node中,应用需要处理网络协议、操作数据库、处理图片、接受上传文件等，在网络流和文件的操作中，还要处理大量二进制数据，javaScript自有的字符串远远不能满足这些需求，于是buffer对象应运而生</p>
<p><strong>「buffer是一个像Array的对象，但它主要用于操作字节」</strong>。</p>
<p><strong>buffer</strong> 是一个javascript与c++结合，buffer所占用的 <strong>内存不是通过V8分配的，属于堆外内存</strong>，由于V8垃圾回收性能的影响，将常用的操作对象用更高效和专有的内存分配回收策略来管理</p>
<p><img src="https://gitee.com/mo_zi_hao/picsBed/raw/master/image/buffer40.png" alt="buffer40"></p>
<h3 id="buffer对象"><a href="#buffer对象" class="headerlink" title="buffer对象"></a>buffer对象</h3><p>buffer元素为 <strong>16进制的两位数，即0到255的数值</strong></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> str = <span class="string">&#x27;hello world,你好&#x27;</span></span><br><span class="line"><span class="keyword">var</span> strBuffer = <span class="keyword">new</span> buffer(str,<span class="string">&#x27;utf-8&#x27;</span>)</span><br><span class="line"><span class="built_in">console</span>.log(strBuffer)   <span class="comment">//&lt;Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64 2c e4 bd a0 e5 a5 bd&gt;</span></span><br></pre></td></tr></table></figure>

<p>不同的编码的字符串占用的元素个数各不相同，上面的代码打印出的中文字在 <strong>utf-8编码下占用3个元素，字母和符号和空格占用1个元素</strong></p>
<p>buffer对象类似于数组，可以 <strong>访问length属性得到长度，也可以通过下标访问元素和给元素赋值</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">var buf &#x3D; new Buffer(100)  &#x2F;&#x2F;分配一个长100字节的Buffer对象</span><br><span class="line">console.log(buf.length) &#x2F;&#x2F; 100</span><br></pre></td></tr></table></figure>

<p><strong>「注意」</strong>:给元素的赋值如果小于0，就将该值逐次加256，直到得到一个0到255之间的整数。如果得到的数值大于255，就逐次减256，直到得到0~255区间内的数值。如果是小数，舍弃小数部分，只保留整数部分</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> strbuf = <span class="keyword">new</span> Buffer(<span class="number">100</span>)</span><br><span class="line">strbuf[<span class="number">0</span>] = -<span class="number">10</span></span><br><span class="line">strbuf[<span class="number">1</span>] = <span class="number">300</span></span><br><span class="line">strbuf[<span class="number">2</span>] = <span class="number">3.14</span></span><br><span class="line"><span class="built_in">console</span>.log(strbuf[<span class="number">0</span>]) <span class="comment">//246      --》 -10+256</span></span><br><span class="line"><span class="built_in">console</span>.log(strbuf[<span class="number">1</span>])  <span class="comment">//44       --》 300-256</span></span><br><span class="line"><span class="built_in">console</span>.log(strbuf[<span class="number">2</span>]) <span class="comment">//3</span></span><br></pre></td></tr></table></figure>

<h3 id="buffer的内存分配"><a href="#buffer的内存分配" class="headerlink" title="buffer的内存分配"></a>buffer的内存分配</h3><p>buffer对象的 <strong>内存分配不是在v8的堆内存中</strong>， 而是在node的c++层面实现内存的申请的。（ <strong>原因</strong>：因为处理大量的字节数据不能采用需要一点内存就向操作系统申请一点内存的方式，这可能造成大量的内存申请的系统调用，对操作系统有一定的压力）</p>
<p><strong>node在内存的使用上应用的是在c++层面申请内存，在javascript中分配内存的策略</strong></p>
<p><strong>node采用了slab分配机制</strong>。slab是一种动态内存管理机制，slab是一块申请好的固定大小的内存区域，<strong>slab具体有以下3种状态：</strong></p>
<ul>
<li>full：完全分配状态</li>
<li>partial：部分分配状态</li>
<li>empty：没有被分配状态</li>
</ul>
<p>Node以<strong>「8KB为界限来区分是大对象还是小对象」</strong>：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Buffer.poolSize &#x3D; 8 * 1024</span><br></pre></td></tr></table></figure>

<p>这个<strong>「8KB的值也就是每个slab的大小值，在javascript层面」</strong>，以它作为单位单元进行内存的分配</p>
<h3 id="分配小buffer对象"><a href="#分配小buffer对象" class="headerlink" title="分配小buffer对象"></a>分配小buffer对象</h3><p>如果指定buffer的大小 <strong>小于8KB</strong>，Node会按照 <strong>小对象的方式进行分配</strong>。Buffer的分配过程中主要使用一个 <strong>局部变量pool作为中间处理对象</strong>，处于分配状态的slab单元都指向它。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> pool</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">allocPool</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">  pool = <span class="keyword">new</span> SlowBuffer(Buffer.poolSize)</span><br><span class="line">  pool.used = <span class="number">0</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>下图为新构造的slab单元示例：此时的slab处于empty状态</p>
<p><img src="https://gitee.com/mo_zi_hao/picsBed/raw/master/image/buffer30.png" alt="buffer30"></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">new Buffer(1024)</span><br></pre></td></tr></table></figure>

<p>当new一个Buffer对象的时候会先检查pool对象是否被创建，没有创建则 <strong>调用allocPool方法</strong>，当前Buffer对象的 <strong>parent属性指向该slab</strong>，<strong>并记录下</strong> 是从这个slab的 <strong>哪个位置(offset)开始使用</strong> 的，slab对象自身也被 <strong>记录使用了多少字节</strong></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">this</span>.parent = slab</span><br><span class="line"><span class="built_in">this</span>.offset = pool.used</span><br><span class="line">pool.used +=<span class="built_in">this</span>.length</span><br></pre></td></tr></table></figure>

<p>如下图为一个<strong>「新的slab单位中初次分配一个buffer对象」</strong>的示意图：（此时的状态为partial）</p>
<p><img src="https://gitee.com/mo_zi_hao/picsBed/raw/master/image/buffer0.png" alt="buffer0"></p>
<p>当 <strong>再次创建Buffer对象</strong> 时，构造过程中将会 <strong>判断这个slab的剩余空间是否足够</strong>。如果 <strong>足够，则使用剩余的空间</strong>，并更新slab的分配状态。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">new Buffer(3000)</span><br></pre></td></tr></table></figure>

<p>再new一个长度3000的Buffer，下图为再次更新slab的分配状态，<strong>判断上一个创建的slab剩余的空间是否足够，如果足够则使用剩余的空间，如果不够将会构造新的slab</strong></p>
<p><img src="https://gitee.com/mo_zi_hao/picsBed/raw/master/image/buffer10.png" alt="buffer10"></p>
<p><strong>「注意」</strong>：同个slab可能分配给多个Buffer对象使用，只有一些小Buffer对象在作用域释放并都可以回收的时候，slab的8KB空间才会被回收。<strong>尽管创建了1个字节的Buffer对象，但如果不释放它，实际可能是8KB的内存没有释放</strong></p>
<h3 id="分配大Buffer对象"><a href="#分配大Buffer对象" class="headerlink" title="分配大Buffer对象"></a>分配大Buffer对象</h3><p>如果需要 <strong>超过8KB的Buffer对象</strong>，将会直接 <strong>分配一个SlowBuffer对象作为slab单元</strong>，这个slab单元将会被这个大Buffer对象占用</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">this.parent &#x3D; new SlowBuffer(this.length)</span><br><span class="line">this.offset &#x3D; 0</span><br></pre></td></tr></table></figure>

<p>这里的 <strong>SlowBuffer类是C++中定义的</strong>，虽然引用Buffer模块可以访问到它，但是 <strong>不推荐直接操作它</strong>，而是 <strong>使用Buffer</strong> 代替, <strong>上面提到的Buffer对象都是javascript层面的，能够被V8的垃圾回收标记回收。但是它内部的parent属性指向的SlowBuffer对象却来自Node自身C++中的定义，是C++层面上的Buffer对象，所用内存不在V8的堆中</strong></p>
<h3 id="Buffer转换"><a href="#Buffer转换" class="headerlink" title="Buffer转换"></a>Buffer转换</h3><p><strong>「Buffer对象可以与字符串之间相互转换」</strong>，目前支持的字符串编码类型有：ASCII、UTF-8、UTF-16LE/UCS-2、Base64、Binary、Hex</p>
<p><strong>「字符串转Buffer」</strong>：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">new Buffer(string,encoding)  &#x2F;&#x2F;旧api</span><br><span class="line">Buffer.from(string,encoding)  &#x2F;&#x2F;新api</span><br></pre></td></tr></table></figure>

<p>存储的只能是一种编码类型，<strong>「encoding参数不传递时，默认按UTF-8编码进行转码和存储」</strong></p>
<p><strong>Buffer对象可以存储不同编码类型的字符串转码的值</strong>，调用 <strong>write()</strong> 方法可以实现该目的</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">buf.write(string,[offset],[length],[encoding])</span><br></pre></td></tr></table></figure>

<p>由于可以不断写入内容到Buffer对象中，并且每次写入可以指定编码，所以Buffer对象中可以存在多种编码转化后的内容。<strong>每种编码所用的字节长度不同，将Buffer反转回字符串时需要谨慎处理</strong></p>
<p><strong>「Buffer转字符串」</strong>:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">buf.toString([encoding],[start],[end])</span><br></pre></td></tr></table></figure>

<p>encoding(默认UTF-8)、start、end这三个参数实现整体或局部的转换，如果Buffer对象由多种编码写入，就需要在局部指定不同的编码，才能转换回正常的编码</p>
<p><strong>「Buffer不支持的编码类型」</strong>: Node的Buffer对象支持的编码类型是有限的，只有少数的几种编码类型可以在字符串和Buffer之间转换。为此，Buffer提供了一个 <strong>isEncoding()</strong> 函数来 <strong>判断编码是否支持转换</strong>：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Buffer.isEncoding(encoding)     &#x2F;&#x2F;返回值为  true &#x2F; false</span><br></pre></td></tr></table></figure>

<p>中国的 <strong>GBK、GB2312、BIG-5编码都不在支持的行列中</strong>，其他就不一一列举了）—-对于不支持的编码类型，可以借助Node生态圈模块完成转换，<strong>iconv和iconv-lite两个模块可以支持更多的编码类型转换</strong></p>
<ul>
<li><strong>iconv-lite</strong>：采用纯javascript实现，更轻量，无需编译和处理环境依赖直接使用，在性能方面，由于转码都是耗用CPU，在V8的高性能下，少了C++到JavaScript的层次转换，纯JavaScript的性能比C++实现更好</li>
<li><strong>iconv</strong>：通过C++调用libiconv库完成。</li>
</ul>
<p><strong>「icon-lite」</strong>:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> iconv = <span class="built_in">require</span>(<span class="string">&#x27;iconv-lite&#x27;</span>)</span><br><span class="line"><span class="comment">//Buffer转字符串</span></span><br><span class="line"><span class="keyword">var</span> str = iconv.decode(buf,<span class="string">&#x27;win1251&#x27;</span>)</span><br><span class="line"><span class="comment">//字符串转buffer</span></span><br><span class="line"><span class="keyword">var</span> buf = iconv.encode(<span class="string">&#x27;Sample input String&#x27;</span>,<span class="string">&#x27;win1251&#x27;</span>)</span><br></pre></td></tr></table></figure>

<p><strong>iconv-lite和iconv对无法转换的内容进行降级处理的方案不尽相同：</strong></p>
<p><strong>「iconv-lite」</strong>:无法转换的多字节会输出�，单字节输出？</p>
<p><strong>「iconv」</strong>：三级降级策略，会尝试翻译无法转换的内容或者忽略这些内容；如果没设置，无法转换的内容会得到EILSEQ异常</p>
<p><strong>「iconv」</strong>：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> iconv = <span class="keyword">new</span> Iconv(<span class="string">&#x27;UTF-8&#x27;</span>,<span class="string">&#x27;ASCII&#x27;</span>)</span><br><span class="line">iconv.convert(<span class="string">&#x27;ça va&#x27;</span>) <span class="comment">//throws EILSEQ异常</span></span><br><span class="line"><span class="keyword">var</span> iconv = <span class="keyword">new</span> Iconv(<span class="string">&#x27;UTF-8&#x27;</span>,<span class="string">&#x27;ASCII//IGNORE&#x27;</span>)</span><br><span class="line">iconv.convert(<span class="string">&#x27;ça va&#x27;</span>)  <span class="comment">//returns &#x27;a va&#x27;</span></span><br><span class="line"><span class="keyword">var</span> iconv = <span class="keyword">new</span> Iconv(<span class="string">&#x27;UTF-8&#x27;</span>,<span class="string">&#x27;ASCII//TRANSLIT&#x27;</span>)</span><br><span class="line">icon.convert(<span class="string">&#x27;ça va&#x27;</span>) <span class="comment">//&quot;ca va&quot;</span></span><br><span class="line"><span class="keyword">var</span> iconv = <span class="keyword">new</span> Iconv(<span class="string">&#x27;UTF-8&#x27;</span>,<span class="string">&#x27;ASCII//TRANSLIT//IGNORE&#x27;</span>)</span><br><span class="line">icon.convert(<span class="string">&#x27;ça va か&#x27;</span>)  <span class="comment">// &quot;ca va &quot;</span></span><br></pre></td></tr></table></figure>

<h3 id="Buffer的拼接"><a href="#Buffer的拼接" class="headerlink" title="Buffer的拼接"></a>Buffer的拼接</h3><p><strong>「乱码产生的原因」</strong>: 从输入流中读取内容</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>)</span><br><span class="line"><span class="keyword">var</span> rs = fs.createReadStream(<span class="string">&#x27;test.md&#x27;</span>)   <span class="comment">//创建可读流</span></span><br><span class="line"><span class="keyword">var</span> data =  <span class="string">&#x27;&#x27;</span></span><br><span class="line">rs.on(<span class="string">&#x27;data&#x27;</span>,<span class="function"><span class="keyword">function</span>(<span class="params">trunk</span>)</span>&#123;</span><br><span class="line">    data += trunk</span><br><span class="line">&#125;)</span><br><span class="line">rs.on(<span class="string">&#x27;end&#x27;</span>,<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(data)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>data事件获取的是trunk对象是Buffer对象，但输入流中有宽字节编码时，会看到�乱码符号</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">data +&#x3D; trunk</span><br><span class="line">这句代码隐藏了toString()操作，等价于 data &#x3D; data.toString() + trunk.toString()</span><br></pre></td></tr></table></figure>

<p>对英文环境下，toString()不会造成任何问题；但是对宽字节的中文，却会形成问题 createReadStream中返回的可读流的highWaterMark（每次读取的个数）的默认值是64，下面我们将上面代码的返回可读流的highWaterMark的值修改为11</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">var rs &#x3D; fs.createReadStream(&#39;test.md&#39;,&#123;highWaterMark: 11&#125;)</span><br></pre></td></tr></table></figure>

<p><strong>test.md文件的内容为：</strong>你好吗,现在我们来学习node.js吧,这一节我们来谈谈Buffer</p>
<p><strong>打印输出的结果为：</strong>你好吗,���在我们来学习node.js吧,��一节我���来谈谈Buffer</p>
<p>由于我们限定了Buffer对象的长度为11，原始Buffer存储为：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;Buffer e4 bd a0 e5 a5 bd e5 90 97 2c ef bf bd ef bf bd ef bf bd e5 9c a8 e6 88 91 e4 bb ac e6 9d a5 e5 ad a6 e4 b9 a0 6e 6f 64 65 2e 6a 73 e5 90 a7 2c ef bf ... &gt;</span><br></pre></td></tr></table></figure>

<p><strong>「原因」</strong>: 上文提到的buf.toString()方法默认以UTF-8编码，中文在UTF-8中占3个字节，符号英文占1个字节，所以第一个Buffer对象输出时，Buffer中的剩下的一个字节（ef）将以乱码显示,所以第二个Buffer中的被截断剩下的两个字节（bf bd）不能形成文字，只能显示乱码了</p>
<p><strong>「结论」</strong>：上面这个例子中我们构造了11这个限制，但是 <strong>对于任意长度的Buffer而言，宽字节字符串都有可能存在被截断的情况，只不过Buffer的长度越大出现的概率越低而已，但该问题依然不可忽视</strong></p>
<h3 id="setEncoding-和string-decoder"><a href="#setEncoding-和string-decoder" class="headerlink" title="setEncoding()和string_decoder()"></a>setEncoding()和string_decoder()</h3><p><strong>「setEncoding()」</strong>: 可读流还有一种设置编码的方法setEncodeing()</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">readabel.setEncoding(encoding)</span><br></pre></td></tr></table></figure>

<p>该方法的作用是让data事件中传递的不再是一个Buffer对象，而是编码后的字符串。下面我们将上面的程序添加setEncoding()</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>)</span><br><span class="line"><span class="keyword">var</span> rs = fs.createReadStream(<span class="string">&#x27;test.md&#x27;</span>,&#123;<span class="attr">highWaterMark</span>: <span class="number">11</span>&#125;)   <span class="comment">//创建可读流</span></span><br><span class="line">rs.setEncoding(<span class="string">&#x27;utf8&#x27;</span>)</span><br><span class="line"><span class="keyword">var</span> data =  <span class="string">&#x27;&#x27;</span></span><br><span class="line">rs.on(<span class="string">&#x27;data&#x27;</span>,<span class="function"><span class="keyword">function</span>(<span class="params">trunk</span>)</span>&#123;</span><br><span class="line">    data += trunk</span><br><span class="line">&#125;)</span><br><span class="line">rs.on(<span class="string">&#x27;end&#x27;</span>,<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(data)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p><strong>输出结果：</strong>你好吗,现在我们来学习node.js吧,这一节我们来谈谈Buffer</p>
<p>最终我们可以得到了满意的结果，说明现在不受Buffer大小的影响，<strong>设置编码并非改变按段读取的方式</strong>，是在 <strong>调用setEncoding()的时候，可读流对象在内部设置了一个decoder对象，每次data事件都通过该decoder对象进行Buffer到字符串的解码</strong>，然后传递给调用者，设置编码后，data不再接收到Buffer对象（<strong>所以宽字节字符串被截断的问题依然存在</strong>）</p>
<hr>
<p><strong>「string_decoder()」</strong>:</p>
<p>decoder对象来自于string_decoder模块的StringDecoder的实例对象</p>
<p>代码示例</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">var StringDecoder &#x3D; require(&#39;string_decoder&#39;).StringDecoder</span><br><span class="line">var decoder &#x3D; new StringDecoder(&#39;utf8&#39;)</span><br><span class="line">var buf1 &#x3D; new Buffer([0xe4,0xbd,0xa0,0xe5,0xa5,0xbd,0xe5,0x90,0x97,0x2c,0xef])</span><br><span class="line">console.log(decoder.write(buf1))  &#x2F;&#x2F;你好吗,</span><br><span class="line"></span><br><span class="line">var buf2 &#x3D; new Buffer([0xbf,0xbd,0xef,0xbf,0xbd,0xef,0xbf,0xbd,0xe5,0x9c,0xa8])</span><br><span class="line">console.log(decoder.write(buf2))  &#x2F;&#x2F;现在</span><br></pre></td></tr></table></figure>

<p><strong>第一次write()时,只输出前9个字节转码形成的字符串,”现“字前一个字节被保留在StringDecoder实例内部。第二次write()时，会将这个剩下的字节和后续的两个字节组合在一起，再次用3的整数倍字节进行转码。于是乱码的问题通过这种中间的形式解决了</strong></p>
<p><strong>「注意」</strong>：string_decoder目前只能处理 <strong>UTF-8</strong> 、<strong>Base64</strong> 和 <strong>UCS-2/UTF-16LE</strong> 这三种编码</p>
<hr>
<h3 id="正确拼接Buffer"><a href="#正确拼接Buffer" class="headerlink" title="正确拼接Buffer"></a>正确拼接Buffer</h3><p>将多个小Buffer对象拼接成一个Buffer对象。通过iconv-lite一类的模块进行转码。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> chunks = []</span><br><span class="line"><span class="keyword">var</span> size = <span class="number">0</span></span><br><span class="line">res.on(<span class="string">&#x27;data&#x27;</span>,<span class="function"><span class="keyword">function</span>(<span class="params">chunk</span>)</span>&#123;</span><br><span class="line">    chunks.push(chunk)</span><br><span class="line">    size +=chunk.length</span><br><span class="line">&#125;)</span><br><span class="line">res.on(<span class="string">&#x27;end&#x27;</span>,<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">var</span> buf = Buffer.concat(chunks,size)</span><br><span class="line">    <span class="keyword">var</span> str = iconv.decode(buf,<span class="string">&#x27;utf8&#x27;</span>)</span><br><span class="line">    <span class="built_in">console</span>.log(str)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>正确的拼接方式是用一个数组来存储接收到的Buffer片段并记录下所有的片段的总长度,然后调用Buffer.concat()方法生成一个合并的Buffer对象。Buffer.concat()方法封装了从小Buffer对象向大Buffer对象的复制过程</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">Buffer.concat = <span class="function"><span class="keyword">function</span>(<span class="params">list,length</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(!<span class="built_in">Array</span>.isArray(list))&#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">&#x27;Usage：Buffer.concat(list,[length])&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(list.length === <span class="number">0</span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> Buffer(<span class="number">0</span>)</span><br><span class="line">    &#125;<span class="keyword">else</span> <span class="keyword">if</span>(list.length === <span class="number">1</span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> list[<span class="number">0</span>]</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span>(<span class="keyword">typeof</span> length !== <span class="string">&#x27;number&#x27;</span>)&#123;</span><br><span class="line">        length = <span class="number">0</span></span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">var</span> i = <span class="number">0</span>;i &lt; list.length;i++)&#123;</span><br><span class="line">            <span class="keyword">var</span> buf = list[i]</span><br><span class="line">            length += buf.length</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">var</span> buffer = <span class="keyword">new</span> Buffer(length)</span><br><span class="line">    <span class="keyword">var</span> pos = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">var</span> i = <span class="number">0</span>;i &lt; length;i++)&#123;</span><br><span class="line">        <span class="keyword">var</span> buf = list[i]</span><br><span class="line">        buf.copy(buffer,pos)</span><br><span class="line">        pos += buf.length</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> buffer</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="Buffer性能"><a href="#Buffer性能" class="headerlink" title="Buffer性能"></a>Buffer性能</h3><p>在网络传输中，需要将数据转换成Buffer，以二进制数据传输。<strong>提高字符串到Buffer的转换，可以大程度提高网络吞吐率</strong></p>
<p>下面例子中构造一个10kb大小的字符串，通过纯字符串的方式向客户端发送</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>)</span><br><span class="line"><span class="keyword">var</span> helloworld = <span class="string">&#x27;&#x27;</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">var</span> i = <span class="number">0</span>;i &lt; <span class="number">1024</span>*<span class="number">100</span>;i++)&#123;</span><br><span class="line">    helloworld += <span class="string">&#x27;你好&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// helloworld = Buffer.from(helloworld)</span></span><br><span class="line">http.createServer(<span class="function"><span class="keyword">function</span>(<span class="params">req,res</span>)</span>&#123;</span><br><span class="line">    res.writeHead(<span class="number">200</span>)</span><br><span class="line">    res.end(helloworld)</span><br><span class="line">&#125;).listen(<span class="number">3000</span>)</span><br></pre></td></tr></table></figure>

<p>我们先执行一下上面的代码，终端：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">node index.js </span><br></pre></td></tr></table></figure>

<p>下面我们使用ab压力测试，来看看性能</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ab -c 200 -t 100 http:&#x2F;&#x2F;127.0.0.1:3000</span><br></pre></td></tr></table></figure>

<p><strong>「ab常用参数介绍」</strong>：</p>
<ul>
<li>-n：总共的请求执行数，缺省是1</li>
<li>-c：并发数，缺省是1</li>
<li>-t：测试所进行的总时间，单位为秒，缺省是50000s</li>
<li>-p：POST时的数据文件</li>
<li>-w：以HTML表的格式输出结果</li>
</ul>
<p>(上面ip要根据自己查查自己本地的，运行 ip config 查看一下自己的ip)</p>
<p><img src="https://gitee.com/mo_zi_hao/picsBed/raw/master/image/buffer60.png" alt="buffer60"></p>
<p><strong>测试的QPS（每秒查询次数）是387.87，传输率为每秒232927.23KB</strong></p>
<p>接下来我们将上面那行转Buffer的代码注释回来, 再测试一下,下面是使用传输前将字符串转Buffer的测试结果:</p>
<p><img src="https://gitee.com/mo_zi_hao/picsBed/raw/master/image/buffer50.png" alt="buffer50"></p>
<p><strong>测试的QPS（每次查询次数）是1556.06，传输率为每秒933752.73KB</strong></p>
<p>(虽然在字符串不是很长的情况下，两者在性能上没多大的差异，但是在字符串长度比较长的时候差距就比较大了如上面的例子）</p>
<p><strong>通过预先转换静态内容为Buffer对象，可以有效的减少CPU的重复使用，节省服务器资源。</strong></p>
<p><strong>「文件读取」</strong>: Buffer的使用除了与字符串的转换有性能损耗外，在文件读取时，有一个highWaterMark设置对性能的影响至关重要，在 <strong>fs.createReadStream(path,options)</strong> 可以传入一下参数</p>
<p><img src="https://mmbiz.qpic.cn/mmbiz_png/MXL370Pc0NYwCU9hfQnViaK96MMAUP9PF0X9Ig05kFBTnvbI1kIPXMQaWwLwNxJrWO9Juibq5mULOuseDiaYmUSzw/640?wx_fmt=png" alt="img"><strong>「fs.createReadStream()的工作方式」:</strong></p>
<p><strong>是在内存中准备一段Buffer</strong>，然后在 <strong>fs.read()</strong> 读取时逐步从磁盘中 <strong>将字节复制到Buffer中</strong>，则从这个Buffer()中 <strong>通过slice()方法取出部分数据作为一个小Buffer对象，再通过data事件传递给调用方</strong>。如果Buffer用完，则重新分配一个；如果有剩余，则继续使用。</p>
<p>每次读取长度就是用户指定的highWaterMark，当如果文件本身没有指定的highWaterMark那么大的时候，那么预先指定的Buffer会有剩余（剩余的空间可以分配给下次读取使用），当剩余的单元数量小于128字节的时候，会重新分配一个新的Buffer对象。</p>
<p><strong>「highWaterMark的大小对性能有两个影响：」</strong></p>
<ul>
<li>1.对Buffer内存的分配和使用有一定的影响</li>
<li>2.highWaterMark设置过小，可能导致系统调用次数过多</li>
</ul>
<p><strong>「结论」</strong>：对于大文件而言，highWaterMark的大小决定触发系统调用和data事件的次数,highWaterMark值的大小，与读取速度的关系：该值越大，读取速度越快</p>
<hr>
<p>最后，上面例子用的一些api可能会有些是旧的api,如果是报错，上官网看看把旧的api换用一下新的就好了 </p>
<p>报错信息：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">(node:19236) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.</span><br></pre></td></tr></table></figure>

<p>新旧api对比：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> Buffer(number)       <span class="comment">//old</span></span><br><span class="line">Buffer.alloc(number)     <span class="comment">//new</span></span><br><span class="line"><span class="keyword">new</span> Buffer(string)       <span class="comment">//old</span></span><br><span class="line">Buffer.from(string)      <span class="comment">//new</span></span><br><span class="line"><span class="keyword">new</span> Buffer(string,encoding)   <span class="comment">//old</span></span><br><span class="line">Buffer.from(string,encoding)  <span class="comment">//new</span></span><br><span class="line"><span class="keyword">new</span> Buffer(...arguments)      <span class="comment">//old</span></span><br><span class="line">Buffer.from(...arguments)     <span class="comment">//new</span></span><br></pre></td></tr></table></figure></article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="mailto:undefined">mozihao</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://mo_zi_hao.gitee.io/blog/posts/28371/">https://mo_zi_hao.gitee.io/blog/posts/28371/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://mo_zi_hao.gitee.io/blog" target="_blank">mozihao</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/blog/tags/Buffer/">Buffer</a></div><div class="post_share"><div class="social-share" data-image="https://gitee.com/mo_zi_hao/picsBed/raw/master/image/%E8%8B%B1%E8%AF%AD%E5%AD%A6%E4%B9%A0%E8%8B%B1%E6%A0%87%E5%A4%A7%E5%85%A8.jpg" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/social-share.js/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/social-share.js/dist/js/social-share.min.js" defer></script></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/blog/posts/19482/"><img class="prev-cover" src="https://gitee.com/mo_zi_hao/picsBed/raw/master/image/0.png" onerror="onerror=null;src='/blog/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">设计模式-单例模式</div></div></a></div><div class="next-post pull-right"><a href="/blog/posts/25418/"><img class="next-cover" src="https://gitee.com/mo_zi_hao/picsBed/raw/master/image/%E8%8B%B1%E8%AF%AD%E5%AD%A6%E4%B9%A0%E8%8B%B1%E6%A0%87%E5%A4%A7%E5%85%A8.jpg" onerror="onerror=null;src='/blog/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">node.js学习总结</div></div></a></div></nav></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="card-info-avatar is-center"><img class="avatar-img" src="https://gitee.com/mo_zi_hao/picsBed/raw/master/image/%E6%B5%B7%E8%B4%BC008.jpg" onerror="this.onerror=null;this.src='/blog/img/friend_404.gif'" alt="avatar"/><div class="author-info__name">mozihao</div><div class="author-info__description">if you risk nothing,then you risk anthing</div></div><div class="card-info-data"><div class="card-info-data-item is-center"><a href="/blog/archives/"><div class="headline">文章</div><div class="length-num">24</div></a></div><div class="card-info-data-item is-center"><a href="/blog/tags/"><div class="headline">标签</div><div class="length-num">16</div></a></div><div class="card-info-data-item is-center"><a href="/blog/categories/"><div class="headline">分类</div><div class="length-num">11</div></a></div></div><a class="button--animated" id="card-info-btn" target="_blank" rel="noopener" href="https://gitee.com/mo_zi_hao"><i class="iconfont icon-gitee-fill-round"></i><span>我的Gitee</span></a><div class="card-info-social-icons is-center"><a class="social-icon" href="https://gitee.com/mo_zi_hao" target="_blank" title="Gitee"><i class="fab iconfont icon-gitee-fill-round"></i></a><a class="social-icon" href="https://github.com/mmCrazy" target="_blank" title="Github"><i class="fab fa-github"></i></a><a class="social-icon" href="https://blog.csdn.net/xiaomohhh?spm=1001.2101.3001.5343" target="_blank" title="CSDN"><i class="fab iconfont icon-csdn"></i></a><a class="social-icon" href="https://gitee.com/mo_zi_hao/picsBed/raw/master/image/qrcode_for_gh_d35478eda980_430.jpg" target="_blank" title="公众号"><i class="fab iconfont icon-weixingongzhonghao"></i></a><a class="social-icon" href="mailto:747304031@qq.com" target="_blank" title="Email"><i class="fas fa-envelope"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn card-announcement-animation"></i><span>公告</span></div><div class="announcement_content">如文章中有哪些错漏，欢迎各位前端的大佬与我交流并指正，谢谢!!</br>邮箱：747304031@qq.com</br>公众号：一起写前端bug</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-3"><a class="toc-link" href="#buffer%E5%AF%B9%E8%B1%A1"><span class="toc-number">1.</span> <span class="toc-text">buffer对象</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#buffer%E7%9A%84%E5%86%85%E5%AD%98%E5%88%86%E9%85%8D"><span class="toc-number">2.</span> <span class="toc-text">buffer的内存分配</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%88%86%E9%85%8D%E5%B0%8Fbuffer%E5%AF%B9%E8%B1%A1"><span class="toc-number">3.</span> <span class="toc-text">分配小buffer对象</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%88%86%E9%85%8D%E5%A4%A7Buffer%E5%AF%B9%E8%B1%A1"><span class="toc-number">4.</span> <span class="toc-text">分配大Buffer对象</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Buffer%E8%BD%AC%E6%8D%A2"><span class="toc-number">5.</span> <span class="toc-text">Buffer转换</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Buffer%E7%9A%84%E6%8B%BC%E6%8E%A5"><span class="toc-number">6.</span> <span class="toc-text">Buffer的拼接</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#setEncoding-%E5%92%8Cstring-decoder"><span class="toc-number">7.</span> <span class="toc-text">setEncoding()和string_decoder()</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%AD%A3%E7%A1%AE%E6%8B%BC%E6%8E%A5Buffer"><span class="toc-number">8.</span> <span class="toc-text">正确拼接Buffer</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Buffer%E6%80%A7%E8%83%BD"><span class="toc-number">9.</span> <span class="toc-text">Buffer性能</span></a></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/blog/posts/1/" title="无题"><img src="https://gitee.com/mo_zi_hao/picsBed/raw/master/image/%E6%B5%B7%E8%B4%BC4.jpg" onerror="this.onerror=null;this.src='/blog/img/404.jpg'" alt="无题"/></a><div class="content"><a class="title" href="/blog/posts/1/" title="无题">无题</a><time datetime="2022-06-05T05:20:17.974Z" title="发表于 2022-06-05 13:20:17">2022-06-05</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/blog/posts/36549/" title="编写可维护的JavaScript (代码习惯)"><img src="https://gitee.com/mo_zi_hao/picsBed/raw/master/image/%E6%B5%B7%E8%B4%BC4.jpg" onerror="this.onerror=null;this.src='/blog/img/404.jpg'" alt="编写可维护的JavaScript (代码习惯)"/></a><div class="content"><a class="title" href="/blog/posts/36549/" title="编写可维护的JavaScript (代码习惯)">编写可维护的JavaScript (代码习惯)</a><time datetime="2022-03-19T03:12:42.624Z" title="发表于 2022-03-19 11:12:42">2022-03-19</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/blog/posts/23125/" title="gitlab-cicd"><img src="https://gitee.com/mo_zi_hao/picsBed/raw/master/image/745.jpg" onerror="this.onerror=null;this.src='/blog/img/404.jpg'" alt="gitlab-cicd"/></a><div class="content"><a class="title" href="/blog/posts/23125/" title="gitlab-cicd">gitlab-cicd</a><time datetime="2021-12-20T14:00:59.661Z" title="发表于 2021-12-20 22:00:59">2021-12-20</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/blog/posts/449/" title="前端js基础"><img src="https://gitee.com/mo_zi_hao/picsBed/raw/master/image/26&amp;gp=0.jpg" onerror="this.onerror=null;this.src='/blog/img/404.jpg'" alt="前端js基础"/></a><div class="content"><a class="title" href="/blog/posts/449/" title="前端js基础">前端js基础</a><time datetime="2021-08-29T15:22:14.600Z" title="发表于 2021-08-29 23:22:14">2021-08-29</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/blog/posts/35506/" title="微信小程序"><img src="https://gitee.com/mo_zi_hao/picsBed/raw/master/image/1234.jpg" onerror="this.onerror=null;this.src='/blog/img/404.jpg'" alt="微信小程序"/></a><div class="content"><a class="title" href="/blog/posts/35506/" title="微信小程序">微信小程序</a><time datetime="2021-08-29T15:22:14.600Z" title="发表于 2021-08-29 23:22:14">2021-08-29</time></div></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2020 - 2023 By mozihao</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="translateLink" type="button" title="简繁转换">繁</button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div id="local-search"><div class="search-dialog"><div class="search-dialog__title" id="local-search-title">本地搜索</div><div id="local-input-panel"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div></div><hr/><div id="local-search-results"></div><span class="search-close-button"><i class="fas fa-times"></i></span></div><div id="search-mask"></div></div><div><script src="/blog/js/utils.js"></script><script src="/blog/js/main.js"></script><script src="/blog/js/tw_cn.js"></script><script src="https://cdn.jsdelivr.net/npm/vanilla-lazyload/dist/lazyload.iife.min.js"></script><script src="/blog/js/search/local-search.js"></script><div class="js-pjax"></div><script id="click-heart" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/click-heart.min.js" async="async" mobile="false"></script><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.js"></script><script src="https://cdn.jsdelivr.net/gh/metowolf/MetingJS@1.2/dist/Meting.min.js"></script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div></body></html>